package com.xiaode.controller.app.file;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Ret;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.redis.Cache;
import com.jfinal.plugin.redis.Redis;
import com.xiaode.common.constant.Const;
import com.xiaode.common.model.*;
import com.xiaode.common.model.dto.file.ConfirmFileDTO;
import com.xiaode.common.model.dto.file.FileInfoDTO;
import com.xiaode.exce.EnumError;
import com.xiaode.plugin.obs.ObsKit;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 文件名称格式 chat/date/type/userIdTimeMillis.type
 * chat/date/type/userIdTimeMillis.type
 *
 * @author HP
 */
public class FileManageService {

    public Ret getUploadMsgFileParams(Integer accountId, Integer userType, String fileInfo, Integer id, Integer type) throws Exception {
        Cache redis = Redis.use();
        List<FileInfoDTO> fileInfoDTOS = JSONUtil.toList(fileInfo, FileInfoDTO.class);
        //上传的文件为空
        if (ObjectUtil.isAllEmpty(fileInfoDTOS)) {
            return Ret.fail().set("error", EnumError.FILE_NULL.getObj());
        }
        for (FileInfoDTO fileInfoDTO : fileInfoDTOS) {
            if (!Const.fileType.contains(fileInfoDTO.getUpType())) {
                return Ret.fail().set("error", EnumError.UPFILE_NOT_ALLOW.getObj());
            }
        }
        //判断可否上传
//        int userId;
//        int userType;
//        if (user instanceof Student) {
//            Student stu = (Student) user;
//            userId = stu.getId();
//            userType = 2;
//        } else {
//            Admin admin = (Admin) user;
//            userId = admin.getId();
//            userType = 1;
//        }
        if (type == 3) {
            //判断当前上传文件用户是否在群中
            ChatGroupUser chatGroupUser = ChatGroupUser.dao.findFirst("SELECT id FROM chat_group_user WHERE chatGroupId = ? AND accountId = ? AND userType = ?", id, accountId, userType);
            if (BeanUtil.isEmpty(chatGroupUser)) {
                return Ret.fail().set("error", EnumError.NOT_IN_GROUP.getObj());
            }
            // 判断禁言
            ChatGroup chatGroup = ChatGroup.dao.findById(id);
            if (chatGroup.getIsEstoppel() && chatGroupUser.getLevel() != 0 && chatGroupUser.getLevel() != 2) {
                return Ret.fail().set("error", EnumError.GROUP_HAS_MUTE.getObj());
            }
        } else {
            //TODO 好友之间判断拉黑,如果被拉黑则不能上传文件
        }

        String fileType = Const.fileType.getType(fileInfoDTOS.get(0).getUpType());
        //判断MD5是否重复
        List<String> collect = fileInfoDTOS.stream().map(fileInfoDTO -> fileInfoDTO.getMd5()).collect(Collectors.toList());
        Kv kv1 = Kv.create().setIfNotNull("md5List", collect).set("serviceType",1);
        //查询filePath
        List<FilePath> filePaths = FilePath.dao.template("findFilePathByMd5", kv1).find();
        Map<String, String> notNeedUpload = filePaths.stream().collect(Collectors.toMap(FilePath::getMd5File, FilePath::getPath, (a, b) -> a));
        Set<String> keySet = notNeedUpload.keySet();
        //过滤不需要上传的见文件
        List<FileInfoDTO> infoDTOS = fileInfoDTOS.stream().filter(fileInfoDTO -> !keySet.contains(fileInfoDTO.getMd5())).collect(Collectors.toList());
        if (ObjectUtil.isAllEmpty(infoDTOS)) {
            return Ret.ok().set("notNeedUpload", notNeedUpload).set("needUpload", null);
        }

        ArrayList<Kv> kvs = new ArrayList<>();
        //生成文件路径和名称
        for (int i = 0; i < infoDTOS.size(); i++) {
            FileInfoDTO fileInfoDTO = infoDTOS.get(i);
            long l = System.currentTimeMillis();
            //修改文件路径
            String fileName;
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
            Calendar instance = Calendar.getInstance();
            String format = dateFormat.format(instance.getTime());
            //生成文件名称
            fileName = "chat/" + format + "/" + fileType + "/" + accountId + l + "_" + i + "." + fileInfoDTO.getUpType();
            redis.setex(Const.filePath.FILE_UPLOAD + fileName,Const.filePath.FILE_TIME,fileInfoDTO.getMd5());
            Kv kv = ObsKit.getUpParams(fileName,1);
            kv.set("md5",fileInfoDTO.getMd5());
            kvs.add(kv);
        }

        return Ret.ok().set("notNeedUpload",notNeedUpload).set("needUpload",kvs);
    }


    /**
     * isThumbnail参数仅图片可用
     */
    public Ret getDownloadUrl(String fileNames, Boolean isThumbnail,Integer businessType) {
        List<String> fileNameList = JSONUtil.toList(fileNames, String.class);
        if (ObjectUtil.isAllEmpty(fileNameList)){
            return Ret.ok().set("downloadUrl",null);
        }
        AtomicBoolean flag = new AtomicBoolean(false);
        //判后缀是否允许下载
        fileNameList.stream().forEach(fileName->{
            String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
            if (!Const.fileType.contains(suffix)) {
                flag.set(true);
            }
        });
        //如果不允许下载
        if (flag.get()){
            return Ret.fail().set("error", EnumError.UPFILE_NOT_ALLOW.getObj());
        }
        Kv pathList = Kv.by("pathList", fileNameList).set("businessType",businessType);
        List<FilePath> filePathList = FilePath.dao.template("findFilePathByFileName", pathList).find();

        //判断是否存在
//        FilePath filePath = FilePath.dao.findFirst("SELECT id FROM file_path WHERE path = ? AND state = 2", fileName);
//        if (BeanUtil.isEmpty(filePath)) {
//            return Ret.fail().set("error", EnumError.FILE_NOT_EXIST.getObj());
//        }
        if (ObjectUtil.isAllEmpty(filePathList)){
            return Ret.fail().set("error", EnumError.FILE_NOT_EXIST.getObj());
        }

        HashMap<String, String> hashMap = new HashMap<>();
        for (FilePath filePath : filePathList) {
            //通过华为云获取下载图片路径   是否是缩略图
            String downloadUrl = ObsKit.getDownloadUrl(filePath.getPath(), isThumbnail,businessType);
            hashMap.put(filePath.getPath(),downloadUrl);
        }
        List<String> list = JSONUtil.toList(fileNames, String.class);
        ArrayList<String> strings = new ArrayList<>();
        for (String s : list) {
            strings.add(hashMap.get(s));
        }
        return Ret.ok("downloadUrl", strings);
    }

    public int getUserId(Object user) throws Exception {
        if (user instanceof Student) {
            return ((Student) user).getId();
        } else {
            return ((Admin) user).getId();
        }
    }

    /**
     * 文件上传成功确认
     *
     * @return
     */
    public Ret confirmUploadFile(String confirmFile,Integer businessType)throws Exception {
        Cache redis = Redis.use();
        List<ConfirmFileDTO> confirmFileDTOS = JSONUtil.toList(confirmFile, ConfirmFileDTO.class);

        ArrayList<FilePath> filePaths = new ArrayList<>();
        ArrayList<String> strings = new ArrayList<>();
        for (ConfirmFileDTO confirmFileDTO : confirmFileDTOS) {
            String key = confirmFileDTO.getKey();
            if (!redis.exists(Const.filePath.FILE_UPLOAD + key)){
                strings.add(key+"文件已过期!");
            }
            String o = redis.get(Const.filePath.FILE_UPLOAD + key);

            if (!Const.fileType.contains(confirmFileDTO.getType())){
                continue;
            }
            if (confirmFileDTO.getMd5().equals(o)){
                FilePath filePath = new FilePath();
                filePath.setPath(key);
                filePath.setMd5File(confirmFileDTO.getMd5());
                filePath.setState(2);
                filePath.setFileType(confirmFileDTO.getType());
                filePath.setServiceType(businessType);
                filePaths.add(filePath);
            }
        }
        Db.batchSave(filePaths,filePaths.size());
        return Ret.ok().set("errMsg",strings);
    }

    /**
     * 获取文件上传参数
     * @param user
     * @param fileInfo
     * @return
     */
    public Ret getUploadFileParams(Integer accountIdMy, String fileInfo) {
        Cache redis = Redis.use();
        List<FileInfoDTO> fileInfoDTOS = JSONUtil.toList(fileInfo, FileInfoDTO.class);
        //上传的文件为空
        if (ObjectUtil.isAllEmpty(fileInfoDTOS)) {
            return Ret.fail().set("error", EnumError.FILE_NULL.getObj());
        }
        for (FileInfoDTO fileInfoDTO : fileInfoDTOS) {
            if (!Const.fileType.contains(fileInfoDTO.getUpType())) {
                return Ret.fail().set("error", EnumError.UPFILE_NOT_ALLOW.getObj());
            }
        }

        String fileType = Const.fileType.getType(fileInfoDTOS.get(0).getUpType());
        //判断MD5是否重复
        List<String> collect = fileInfoDTOS.stream().map(fileInfoDTO -> fileInfoDTO.getMd5()).collect(Collectors.toList());
        Kv kv1 = Kv.create().setIfNotNull("md5List", collect).set("serviceType",2);
        //查询filePath
        List<FilePath> filePaths = FilePath.dao.template("findFilePathByMd5", kv1).find();
        Map<String, String> notNeedUpload = filePaths.stream().collect(Collectors.toMap(FilePath::getMd5File, FilePath::getPath, (a, b) -> a));
        Set<String> keySet = notNeedUpload.keySet();
        //过滤不需要上传的见文件
        List<FileInfoDTO> infoDTOS = fileInfoDTOS.stream().filter(fileInfoDTO -> !keySet.contains(fileInfoDTO.getMd5())).collect(Collectors.toList());
        if (ObjectUtil.isAllEmpty(infoDTOS)) {
            return Ret.ok().set("notNeedUpload", notNeedUpload).set("needUpload", null);
        }

        ArrayList<Kv> kvs = new ArrayList<>();
        //生成文件路径和名称
        for (int i = 0; i < infoDTOS.size(); i++) {
            FileInfoDTO fileInfoDTO = infoDTOS.get(i);
            long l = System.currentTimeMillis();
            //修改文件路径
            String fileName;
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
            Calendar instance = Calendar.getInstance();
            String format = dateFormat.format(instance.getTime());
            //生成文件名称
            fileName = "xiaode/" + format + "/" + fileType + "/" + accountIdMy + l + "_" + i + "." + fileInfoDTO.getUpType();
            redis.setex(Const.filePath.FILE_UPLOAD + fileName,Const.filePath.FILE_TIME,fileInfoDTO.getMd5());
            Kv kv = ObsKit.getUpParams(fileName,2);
            kv.set("md5",fileInfoDTO.getMd5());
            kvs.add(kv);
        }
        return Ret.ok().set("notNeedUpload",notNeedUpload).set("needUpload",kvs);
    }
}
